#include <stdio.h>

/*
	用 sizeof 计算。一个指针 4个字节。

	float (*a1)[3]； 一个指针 指向有3个元素的数组。 4个字节

	char (*a4)[3]； 一个指针 指向有3个元素的数组。 4个字节

	float *a2[3]； 指针数组，有3个 指针。 12个字节。

	char *a5[3]; 指针数组，有3个 指针。 12个字节。

	float a3[3]; float 数组,有3个元素，sizeof(float) * 3 = 12 个字节

	char a6[3]; char 数组,有3个元素，sizeof(char) * 3 = 3 个字节.
*/
void v()
{
	char *p[5];
	
	printf("sizeof(*p[5]) = %d %d %d\n", sizeof(*p[4]), sizeof(p[4]), sizeof(p));		// 1 4 20
	printf("sizeof(*p[5]) = %d %d %d\n", sizeof(p[4][0]), sizeof(*p[0]), sizeof(*p));	// 1 1 4
}

int array(void)
{
	int zippo[4][2] = { {2,4}, {6, 8}, {1, 3}, {5, 7} };

													// zippo = 0x7ffdf09e2b90 , zippo + 1 = 0x7ffdf09e2b98  0x7ffdf09e2b98
	printf(" zippo = %p\t, zippo + 1 = %p  %p\n", 	zippo, zippo + 1, &zippo[1][0]); // zippo + 1 换到下一行的首地址

													// zippo[0] = 0x7ffdf09e2b90      , zippo[0] + 1 = 0x7ffdf09e2b94
	printf(" zippo[0] = %p\t, zippo[0] + 1 = %p\n", zippo[0], zippo[0] + 1);		 // zippo[0] + 1 第一列的第二个元素地址

													// *zippo = 0x7ffdf09e2b90        , *zippo + 1 = 0x7ffdf09e2b94
	printf(" *zippo = %p\t, *zippo + 1 = %p\n\n", 	*zippo, *zippo + 1);			 // *zippo + 1 第一列的第二个元素地址
								
	printf(" &zippo = %p\n\n", 	&zippo);		// &zippo = 0x7ffdf09e2b90
	printf(" zippo[][] = %p\n", zippo[0][0]);	// 2
	
	printf(" zippo[0][0] = %d\n", 	zippo[0][0]);	// 2
	printf(" *zippo[0] = %d\n", 	*zippo[0]);	// 2
	printf(" **zippo = %d\n", 	**zippo);	// 2
	printf(" zippo[2][1] = %d\n", 	zippo[2][1]);	// 3
	printf(" *(*(zippo + 2) + 1) = %d\n", 	* ( * (zippo + 2) + 1));	// 3

	return 0;

}

int array_point(void)
{
	int zippo[4][2] = { {2,4}, {6, 8}, {1, 3}, {5, 7} };
	int (*pz)[2];
	int *pp[4];

	pz = zippo;
/*
	pp = zippo;	// error. int *[4] from type int (*)[2];
	pp = zippo[0][0];	// int *[4] from type int
	pp = &zippo[0][0];	// int *[4] from type int *
	pp = &zippo[0];		// int *[4] from type int (*)[2]
	pp = zippo[0];		// int *[4] from type int
*/
	pp[0] = &zippo[0];	  // warning 
	pp[0] = zippo[0];
	pp[0] = zippo[0][0];	// warning
	pp[0] = &zippo[0][0];
	

	printf("&zippo = %p : %p\n", &zippo, &zippo[1][0]);	
	printf(" pz = %p\t, pz + 1 = %p\n", 		pz, pz + 1);		// 换到下一行的首地址
	printf(" pz[0] = %p\t, pz[0] + 1 = %p\n", 	pz[0], pz[0] + 1);	// 第一列的第二个元素地址
	printf(" *pz = %p\t, *pz + 1 = %p\n", 		*pz, *pz + 1);		// 第一列的第二个元素地址
	printf(" pz[1] = %p\n\n", 		pz[1]);							// 换到下一行的首地址
	
	printf(" pz[0][0] = %d\n", 			pz[0][0]);	// 2
	printf(" *pz[0] = %d\n", 			*pz[0]);	// 2
	printf(" **pz = %d\n", 				**pz);		// 2
	printf(" pz[2][1] = %d\n",			pz[2][1]);	// 3
	printf(" *(*(pz + 2) + 1) = %d\n", 		* ( * (pz + 2) + 1) );	// 3

	return 0;

}

void evaluate()
{
	int *pt;		// C primer plus  P281
	int (*pa)[3];
	
	int ar1[2][3];
	int ar2[3][2];
	
	int **p2;

	pt = &ar1[0][0];
	pt = ar1[0];
	pt = ar1;	// warning: assignment from incompatible pointer type
	
	pa = ar1;
	pa = ar2;	// warning: assignment from incompatible pointer type
	
	p2 = &pt;
	*p2 = ar1[0];
	*p2 = ar2[0];
	p2 = ar2;	// warning: assignment from incompatible pointer type
}

/*
 “数组名被改写成一个指针参数”规则并不是递归定义的。数组的数组会被改写成“数组的指针”，而不是“指针的指针”：

	实参                                                      所匹配的形参

	数组的数组          char c[8][10];							char (*)[10];			数组指针

	指针数组             char *c[10];							char **c;               指针的指针

	数组指针(行指针)  char (*c)[10];							char (*c)[10];			不改变

	指针的指针           char **c;								char **c;               不改变

*/

int _tmain(int argc, char * argv[]) 
{     
	int arr1[3];     
	int arr2[3];     
	int arr3[3];     
	
	int * ptr;     
	
	// ptr1是一个指向 int [3] 的指针，即ptr的类型和&arr1的类型是一样的，注意：arr1指向的内存区域定长     

	int ptr1[3][3] = {{1,2,3},{1,2,3},{1,2,3}};     

	
	// ptr2是一个指向 int * 的指针，即ptr2的类型和&ptr是一样的，注意：ptr指向的内存区域不定长    
	
	int * ptr2[3] = {arr1,arr2,arr3};     
	

	// ptr3是一个指向 int [3] 的指针，即ptr3的类型和&arr1的类型是一样的，注意：arr1指向的内存区域定长  
	
	int(* ptr3)[3] = &arr1;     ptr3=ptr1; // 没错，他们的类型相同  
	

	// ptr3 = ptr2;	// error 无法从“int *[3]”转换为“int (*)[3]  
	

	// ptr4是一个指向 int * 的指针，即ptr4的类型和&ptr是一样的，注意：ptr指向的内存区域不定长  
	
	int ** ptr4;     //ptr4 = &arr1; //error 无法从“int (*)[3]”转换为“int **    
	

	ptr4 = ptr2; // 没错，他们的类型相同  
	
	// ptr4 = ptr3; // error 无法从“int (*)[3]”转换为“int **     
	
	return 0; 
}

int main()
{
	//v();
	array();
	//array_point();
	
	return 0;
}


